package org.darcy.framework.aspect;

import static org.darcy.framework.constant.SysConstant.LOGIN_USER;

import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.darcy.entity.privilege.SysUser;
import org.darcy.entity.sys.SysLog;
import org.darcy.framework.schedule.LogQueue;
import org.darcy.utils.common.DateUtil;
import org.darcy.utils.common.IpUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.json.JSONUtil;
import io.swagger.v3.oas.annotations.Operation;

/**
 * 日志接口切面
 * 
 * https://www.cnblogs.com/fps2tao/p/17335070.html
 */
@Aspect
@Component
public class RequestLogAspect {

	@Autowired
	private LogQueue logQueue;

	@Pointcut(" execution(* org.darcy.controller..*.*(..)) ")
	public void pointcut() {
	}

	@Around("pointcut()")
	public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
		ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		HttpServletRequest request = attributes.getRequest();
		Map<String, Object> operContentMap = new HashMap<>();
		MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
		String declaringTypeName = methodSignature.getDeclaringTypeName();
		String methodName = methodSignature.getMethod().getName();
		operContentMap.put("className", declaringTypeName);
		operContentMap.put("methodName", methodName);
		Map<String, Object> paramMap = this.getRequestParams(proceedingJoinPoint);
		operContentMap.putAll(paramMap);
		Operation annotation = methodSignature.getMethod().getAnnotation(Operation.class);
		if (annotation != null) {
			String value = annotation.summary();
			if (StringUtils.isNotBlank(value)) {
				operContentMap.put("OperationValue", value);
			}

			String content = JSONUtil.toJsonStr(operContentMap);
			Calendar c = Calendar.getInstance();
			SysLog logRecord = SysLog.builder().ip(IpUtils.getRemoteIP(request)).operContent(content)
					.operType(getModuleName(declaringTypeName)).source(value).year(c.get(Calendar.YEAR))
					.month(c.get(Calendar.MONTH) + 1).day(c.get(Calendar.DAY_OF_MONTH))
					.date(DateUtil.format(c.getTime(), "yyyy-MM-dd")).dateTime(c.getTime()).build();

			SysUser user = this.getSubject(request);
			if (user != null) {
				logRecord.setUserName(user.getUsername());
				logRecord.setUid(user.getId());
			} else {
				user = (SysUser) paramMap.get("loginUser");
				logRecord.setUserName(user == null ? "未登录用户" : user.getUsername());
			}
			logQueue.put(JSONUtil.toJsonStr(logRecord));
		}
		return proceedingJoinPoint.proceed();
	}

	/**
	 * 获取模块名称
	 */
	private String getModuleName(String declaringTypeName) {
		if (declaringTypeName.startsWith("org.darcy.controller.auth")) {
			return "登录登出";
		} else if (declaringTypeName.startsWith("org.darcy.controller.base")) {
			return "基础模块";
		} else if (declaringTypeName.startsWith("org.darcy.controller.business")) {
			return "商务管理";
		} else if (declaringTypeName.startsWith("org.darcy.controller.check")) {
			return "项目管理";
		} else if (declaringTypeName.startsWith("org.darcy.controller.index")) {
			return "首页统计";
		} else if (declaringTypeName.startsWith("org.darcy.controller.org")) {
			return "组织架构";
		} else if (declaringTypeName.startsWith("org.darcy.controller.privilege")) {
			return "组织架构";
		} else if (declaringTypeName.startsWith("org.darcy.controller.auth")) {
			return "登录登出";
		} else if (declaringTypeName.startsWith("org.darcy.controller.sys")) {
			return "系统模块";
		} else if (declaringTypeName.startsWith("org.darcy.controller.work")) {
			return "工作任务";
		} else {
			return "default";
		}
	}

	/**
	 * 获取入参
	 */
	private Map<String, Object> getRequestParams(ProceedingJoinPoint proceedingJoinPoint) {
		Map<String, Object> requestParams = new HashMap<>();
		// 参数名
		String[] paramNames = ((MethodSignature) proceedingJoinPoint.getSignature()).getParameterNames();
		// 参数值
		Object[] paramValues = proceedingJoinPoint.getArgs();
		for (int i = 0; i < paramNames.length; i++) {
			Object value = paramValues[i];
			// 如果是文件对象
			if (value instanceof MultipartFile) {
				MultipartFile file = (MultipartFile) value;
				value = file.getOriginalFilename(); // 获取文件名
				requestParams.put(paramNames[i], value);
			} else if (value instanceof HttpServletRequest || value instanceof HttpServletResponse) {
				continue;
			} else {
				requestParams.put(paramNames[i], value);
			}
		}
		return requestParams;
	}

	/**
	 * 获取当前登录用户的信息
	 */
	public SysUser getSubject(HttpServletRequest request) {
		if (StpUtil.isLogin()) {
			Object loginId = StpUtil.getLoginId();
			SaSession session = StpUtil.getSessionByLoginId(loginId);
			if (session != null) {
				SysUser user = (SysUser) session.get(LOGIN_USER);
				return user;
			}
		}
		return null;
	}

}
